package main

import (
	"encoding/json"
	"github.com/gorilla/websocket"
	"log"
	"strings"
	"time"
)

// 消息类型
const (
	danmuMsg = 1 // 弹幕
	bannedMsg = 2 // 禁言
	joinMsg = 3 // 进入房间
	metaMsg = 4 // 房间信息
	errorMsg = 9 // 错误信息
)

const (
	deadline = 5 * time.Second // 超时时间
	pongWait = 60 * time.Second // pong等待时间
	pingPeriod = (pongWait * 9)/10 // ping频率
	maxMessageSize = 512 // 最大读取数据大小
)

const roomDanMuMsg = "roomDanMuMsg"

type Client struct {
	conn *websocket.Conn
	msg RsvData

	room *Room

	// 客户端弹幕缓存数据量
	bufChan chan []byte

	//User
}

type User struct {
	nickname string
}

type Data struct {
	MsgType int
	Msg string
}

type RsvData struct {
	Data
	Token string
}

type WriteData struct {
	Data
}

func (c *Client) writeMsg() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.conn.Close()
	}()

	for {
		select {
		case msg, ok := <-c.bufChan:
			c.conn.SetWriteDeadline(time.Now().Add(deadline))
			// c.bufChan通道已关闭
			if !ok {
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}
			// todo 消息类型可配置
			// 暂时只支持文本信息
			w, err := c.conn.NextWriter(websocket.TextMessage)
			if err != nil {
				return
			}
			w.Write(msg)

			// 发送缓存中的信息
			n := len(c.bufChan)
			for i := 0; i < n; i++ {
				w.Write(<-c.bufChan)
			}

			// 冲洗信息写入流
			// 并不是关闭TCP连接
			// 这里应该w.Flush()更贴切
			if err := w.Close(); err != nil {
				return
			}
		case <-ticker.C:
			c.conn.SetWriteDeadline(time.Now().Add(deadline))
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

func (c *Client) readMsg() {
	defer func() {
		c.conn.Close()
		c.room.leaving <-c
	}()

	c.conn.SetReadLimit(maxMessageSize)
	c.conn.SetReadDeadline(time.Now().Add(pongWait))
	c.conn.SetPongHandler(func(string) error {
		c.conn.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})
	for {
		_, msg, err:= c.conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("error: %v", err)
			}
			break
		}

		rsvData := RsvData{}
		json.Unmarshal(msg, &rsvData)

		writeMsg := WriteData{}
		//if rsvData.Token == "" {
		//	writeMsg.Msg = "log in please"
		//	writeMsg.MsgType = errorMsg
		//	goto write
		//}

		go c.storage()

		danmakuMsg := c.filter(rsvData.Msg)
		writeMsg.MsgType = danmuMsg
		writeMsg.Msg = danmakuMsg

		byteMsg, _ := json.Marshal(writeMsg)

//write:
		nsqData := NsqMsg{RoomId: c.room.id, Msg: byteMsg}
		writeByte, _ := json.Marshal(nsqData)
		NsqSend(roomDanMuMsg, writeByte)
		//c.room.broadcastMsg <- byteMsg
	}
}

func (c *Client) storage() {

}

func (c *Client) filter(msg string) string {
	matched := trieTree.Search(msg)
	if len(matched) != 0 {
		var oldNew []string
		for _, v := range matched {
			oldNew = append(oldNew, v, "***")
		}
		replacer := strings.NewReplacer(oldNew...)
		return replacer.Replace(msg)
	}
	return msg
}